﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Drawing;
using System.Diagnostics;
using System.Globalization;

namespace TallComponents.Web.Pdf
{
    /// <summary>
    /// Stores request parameters for a page preview generation.
    /// </summary>
    internal class PreviewRequesParameters : RequestParameters
    {

        /// <summary>
        /// Gets the rotations.
        /// </summary>
        public int[] Rotation { get; private set; }
        public PointF[] Locations { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="PreviewRequesParameters"/> class.
        /// </summary>
        /// <param name="values">The values.</param>
        public PreviewRequesParameters(NameValueCollection values)
            : base(values)
        {
            Rotation = UnpackRotation(values[ROTATIONKEY], FirstPageIndex, LastPageIndex);
            Locations = ParseLocations(values[LAYOUTINSTRUCTIONSKEY]);
        }

        private PointF[] ParseLocations(string instructions)
        {
            //get the pairs of coordinates
            string[] points = instructions.Split(new char[]{';'}, StringSplitOptions.RemoveEmptyEntries);
            PointF[] result = new PointF[points.Length];

            for (int pointIndex = 0; pointIndex < points.Length; pointIndex++)
            {
                string[] nums = points[pointIndex].Split(new char[]{':'}, StringSplitOptions.RemoveEmptyEntries);
                Debug.Assert(nums.Length == 2, "wrong coordinates are recieved from the client");

                float x = float.Parse(nums[0],CultureInfo.InvariantCulture);
                float y = float.Parse(nums[1], CultureInfo.InvariantCulture);
                result[pointIndex] = new PointF(x,y);
            }

            return result;
        }

        /// <summary>
        /// Unpacks the rotation information from the hex string to the array.
        /// </summary>
        /// <param name="rotationInfo">The rotation info.</param>
        /// <param name="firstPageIndex">First index of the page.</param>
        /// <param name="lastPageIndex">Last index of the page.</param>
        /// <returns>An array containing a rotation degree for the each page</returns>
        private int[] UnpackRotation(string rotationInfo, int firstPageIndex, int lastPageIndex)
        {
            //no rotation if parametr is undefined
            if (string.IsNullOrEmpty(rotationInfo) || rotationInfo.Equals("nan", StringComparison.InvariantCultureIgnoreCase))
                return new int[] { 0 };

            //
            if (firstPageIndex > lastPageIndex)
                lastPageIndex = firstPageIndex;

            //convert hex string to an integer
            long d = Convert.ToInt64(rotationInfo, 16);

            //convert the integer to binary string
            string bin = Convert.ToString(d, 2);

            //calculate the amount of the pages
            int pagesCount = lastPageIndex - firstPageIndex + 1; 

            int[] result = new int[pagesCount];

            for (int pageIndex = pagesCount - 1; pageIndex >= 0; pageIndex--)
            {
                int startPosition = bin.Length - (pagesCount - pageIndex) * 2;
                if (startPosition == -1)
                    startPosition = 0;
                else if (startPosition < -1)
                    break;

                int length = (startPosition == 0 && bin.Length % 2 != 0) ? 1 : 2;

                if (pageIndex == 0)
                    startPosition = 0;

                string pageBin = bin.Substring(startPosition, length);
                int rotation = Convert.ToInt32(pageBin, 2);
                result[pageIndex] = rotation * 90;
            }

            return result;
        }
    }
}
